package com.car.order.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.car.commons.core.model.Result;
import com.car.commons.web.util.RedisKeyUtil;
import com.car.commons.web.util.RedisUtil;
import com.car.commons.web.util.StateUtil;
import com.car.order.annotation.GoodsOrderLogAnnotation;
import com.car.order.client.CarAccountClient;
import com.car.order.client.CarShoppingClient;
import com.car.order.client.model.account.user.UserDto;
import com.car.order.client.model.shopping.goodsInfo.GoodsInfoDto;
import com.car.order.config.AlipayConfiguration;
import com.car.order.dto.alipay.PagePayParam;
import com.car.order.dto.goodOrderInfo.GoodOrderInfoDto;
import com.car.order.dto.goodOrderInfo.GoodsInfoDetail;
import com.car.order.dto.goodOrderInfo.PayOrderForm;
import com.car.order.dto.goods.GoodsDto;
import com.car.order.entity.GoodOrderInfo;
import com.car.order.entity.GoodOrderLog;
import com.car.order.entity.form.goodOrderInfo.*;
import com.car.order.entity.param.goodsOrderInfo.GoodOrderInfoInsertParam;
import com.car.order.exception.goodsOrderInfo.GoodsOrderInfoException;
import com.car.order.exception.goodsOrderInfo.GoodsOrderInfoExceptionCode;
import com.car.order.mapper.GoodOrderInfoMapper;
import com.car.order.mapper.GoodOrderLogMapper;
import com.car.order.service.GoodOrderInfoService;
import com.car.commons.core.model.WoniuException;
import com.car.order.service.GoodOrderLogService;
import com.car.order.util.AlipayUtil;
import com.car.order.util.GoodsOrderDescConstants;
import com.car.order.util.PageDtoUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 杜岷芫
 * @since 2024-08-28 19:00:13
 */
@Service
@Slf4j
public class GoodOrderInfoServiceImpl extends ServiceImpl<GoodOrderInfoMapper, GoodOrderInfo> implements GoodOrderInfoService {

    @Resource
    private GoodOrderInfoMapper goodOrderInfoMapper;
    @Resource
    private CarAccountClient carAccountClient;
    @Resource
    private CarShoppingClient carShoppingClient;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private AlipayUtil alipayUtil;
    @Resource
    private AlipayConfiguration alipayConfiguration;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private GoodOrderLogMapper goodOrderLogMapper;
    @Resource
    private GoodOrderLogService goodOrderLogService;

    @Override
    public Page<GoodOrderInfoDto> findPage(GoodOrderInfoFindPageForm form) {
        Page<GoodOrderInfo> page = new Page<>(form.getPageNum()==null?1:form.getPageNum(),form.getPageSize()==null?6:form.getPageSize());
        QueryWrapper<GoodOrderInfo> query = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(form.getGoodOrderId())) {
            query.like("good_order_id", form.getGoodOrderId());
        }
        if (ObjectUtil.isNotEmpty(form.getOrderState())) {
            query.eq("order_state", form.getOrderState());
        }
        Page<GoodOrderInfo> goodOrderInfoPage = goodOrderInfoMapper.selectPage(page, query);
        Page<GoodOrderInfoDto> goodOrderInfoDtoPage1 = PageDtoUtil.convertPage(goodOrderInfoPage,GoodOrderInfoDto.class);

        return goodOrderInfoDtoPage1;
    }

    @Override
    public List<GoodOrderInfo> findList(GoodOrderInfoFindListForm form){
        QueryWrapper<GoodOrderInfo> query = new QueryWrapper<>();
        return goodOrderInfoMapper.selectList(query);
    }

    @Override
    public GoodOrderInfo findById(String id) {
        return goodOrderInfoMapper.selectById(id);
    }

    @Override
    @Transactional
    @GoodsOrderLogAnnotation(desc = GoodsOrderDescConstants.USER_CREATE)
    public GoodOrderInfoDto insert(GoodOrderInfoInsertParam form) throws Exception{
        //判断用户
        Result<UserDto> result = carAccountClient.findUserById(form.getUserId());
        if (result.getCode() != 200) {
            throw new WoniuException(result.getCode(), result.getMsg());
        }
        UserDto userDto = result.getData();
        if (ObjectUtil.isEmpty(userDto)) {
            throw new WoniuException(500, "用户不存在");
        }
        if (!userDto.getUserState().equals(StateUtil.USER_STATE_NORMAL)) {
            throw new WoniuException(500, "用户状态异常");
        }
        System.out.println("userDto"+userDto);
        //判断商品
        Set<GoodsDto> goods = form.getGoods();
        Set<Integer> goodsIds = goods.stream().map(GoodsDto::getGoodsId).collect(Collectors.toSet());
        Result<List<GoodsInfoDto>> goodsListResult = carShoppingClient.findGoodsInfoListByIds(goodsIds);
        if (goodsListResult.getCode() != 200) {
            throw new WoniuException(goodsListResult.getCode(), goodsListResult.getMsg());
        }
        List<GoodsInfoDto> goodsInfoDtos = goodsListResult.getData();
        if (goodsInfoDtos.size() != goodsIds.size()) {
            throw new GoodsOrderInfoException(500, "有商品信息没找到");
        }
        Set<GoodsInfoDto> collect = goodsInfoDtos.stream().filter(o -> o.getGoodsState().equals(StateUtil.GOODS_STATE_DISABLED)).collect(Collectors.toSet());
        if (ObjectUtil.isNotEmpty(collect) || collect.size() != 0) {
            throw new WoniuException(500, "有商品状态异常");
        }
        //判断库存量
        ArrayList<GoodsInfoDetail> goodsInfoDetails = new ArrayList<>();
        BigDecimal money = new BigDecimal(0);
        for (GoodsInfoDto goodsInfoDto : goodsInfoDtos) {
            for (GoodsDto good : goods) {
                if (good.getGoodsId().equals(goodsInfoDto.getGoodsId())) {
                    if (good.getGoodsCont() <= 0) {
                        throw new WoniuException(500, "商品数量错误");
                    }
                    if (good.getGoodsCont() > goodsInfoDto.getGoodsStock()) {
                        throw new WoniuException(500, "有商品库存不足");
                    }
                    BigDecimal multiply = new BigDecimal(good.getGoodsCont()).multiply(goodsInfoDto.getGoodsPrice());
                    money = money.add(multiply);
                    GoodsInfoDetail goodsInfoDetail = BeanUtil.toBean(goodsInfoDto, GoodsInfoDetail.class);
                    goodsInfoDetail.setGoodsCont(good.getGoodsCont());
                    goodsInfoDetails.add(goodsInfoDetail);
                }
            }
        }
        //加锁修改库存量
        //生成单锁集合，装入单锁
        ArrayList<RLock> rLocks = new ArrayList<>();
        for (Integer goodsId : goodsIds) {
            RLock lock = redissonClient.getFairLock(RedisKeyUtil.lockOrderGoodsId(goodsId));
            rLocks.add(lock);
        }
        //用单锁集合生成多锁
        RLock multiLock = redissonClient.getMultiLock(rLocks.toArray(new RLock[0]));
        multiLock.lock();
        try {
            //修改库存量
            Result updateGoodsStock = carShoppingClient.reduceStockAndAddFreezeStock(form.getGoods());
            if (updateGoodsStock.getCode() != 200) {
                throw new WoniuException(updateGoodsStock.getCode(), updateGoodsStock.getMsg());
            }
        } catch (Exception e) {
//            throw e;
        } finally {
            multiLock.unlock();
        }

        //生成订单
        GoodOrderInfo goodOrderInfo = BeanUtil.toBean(form, GoodOrderInfo.class);
        //生成订单号
        Snowflake snowflake = new Snowflake(1, 1);
        String idStr = snowflake.nextIdStr();
        goodOrderInfo.setGoodOrderId(idStr);
        goodOrderInfo.setUserPhone(userDto.getUserPhone());
        //订单生成时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = LocalDateTime.now().format(formatter);
        goodOrderInfo.setOrderCreatTime(format);
        //生成订单详情
        goodOrderInfo.setOrderDetail(goodsInfoDetails);
        //生成总价
        goodOrderInfo.setMoney(money);
        boolean save = save(goodOrderInfo);
        if (!save) {
            throw new WoniuException(500, "新增失败");
        }
        //订单进入延迟队列
        rabbitTemplate.convertAndSend("goods_order_check_delay_queue", idStr);
        //redis中存储最后支付期限
        LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(15);
        //转时间戳
        long time = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        redisUtil.saveObject(RedisKeyUtil.payOrderTime(idStr), time + "", 15 * 60);
        GoodOrderInfoDto goodOrderInfoDto = BeanUtil.toBean(goodOrderInfo, GoodOrderInfoDto.class);
        goodOrderInfoDto.setUserName(userDto.getUserName());
        return goodOrderInfoDto;
    }

    @Override
    public GoodOrderInfo update(GoodOrderInfoUpdateForm form) {
        GoodOrderInfo goodOrderInfo = BeanUtil.toBean(form, GoodOrderInfo.class);
        boolean b = updateById(goodOrderInfo);
        if (!b) {
            throw new WoniuException(500, "修改失败");
        }
        return goodOrderInfo;
    }

    @Override
    public void delete(Integer id) {
        int i=goodOrderInfoMapper.deleteById(id);
        if (i == 0) {
            throw new WoniuException(500, "删除失败");
        }
    }

    @Override
    public Page<GoodOrderInfoDto> findPageByUserId(GoodOrderInfoFindPageByUserIdForm form) {
        Page<GoodOrderInfo> page = new Page<>(form.getPageNum()==null?1:form.getPageNum(),form.getPageSize()==null?6:form.getPageSize());
        QueryWrapper<GoodOrderInfo> query = new QueryWrapper<>();
        query.eq("user_id", form.getUserId());
        if (ObjectUtil.isNotEmpty(form.getGoodOrderId())) {
            query.like("good_order_id", form.getGoodOrderId());
        }
        if (ObjectUtil.isNotEmpty(form.getOrderState())) {
            query.eq("order_state", form.getOrderState());
        }
        Page<GoodOrderInfo> goodOrderInfoPage = goodOrderInfoMapper.selectPage(page, query);
        Page<GoodOrderInfoDto> goodOrderInfoDtoPage = PageDtoUtil.convertPage(goodOrderInfoPage,GoodOrderInfoDto.class);
        return goodOrderInfoDtoPage;
    }

    @Override
    @GoodsOrderLogAnnotation(desc = GoodsOrderDescConstants.USER_PAID)
    public String payOrder(PayOrderForm form, Integer userId) throws Exception {
        GoodOrderInfo goodOrderInfo = goodOrderInfoMapper.selectById(form.getOrderId());
        if (ObjectUtil.isEmpty(goodOrderInfo)){ throw new GoodsOrderInfoException(GoodsOrderInfoExceptionCode.GOODS_ORDER_INFO_NOT_EXIST);}
        if (!goodOrderInfo.getOrderState().equals(StateUtil.GOODS_ORDER_STATE_UNPAID)) {
            throw new GoodsOrderInfoException(GoodsOrderInfoExceptionCode.GOODS_ORDER_INFO_STATE_ERROR);
        }
        if (!redisUtil.hasKey(RedisKeyUtil.payOrderTime(form.getOrderId()))) {
            throw new WoniuException(500,"订单已超时");
        }
        long time = Long.parseLong(redisUtil.getObject(RedisKeyUtil.payOrderTime(form.getOrderId())).toString());
        long now = System.currentTimeMillis();
        if ((time - now) / 1000 < 60) {
            throw new Exception("订单已超时");
        }
        PagePayParam param = new PagePayParam();
        //以下参数根据实际情况设置l
        param.setMoney(goodOrderInfo.getMoney().doubleValue());
        param.setSubject("订单支付");
        param.setBody("");
        param.setReturnUrl(form.getReturnUrl());
        param.setNotifyUrl("http://iqq6v9.natappfree.cc/goodOrderInfo/notify");
        param.setPayTimeBorder(15);
        param.setOrderId(form.getOrderId());
        String page = alipayUtil.pagePay(param);
        return page;
    }

    @Override
    public void payNotify(HashMap<String, String> params) throws AlipayApiException {
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfiguration.getAlipayPublicKey(), "utf-8", "RSA2");
        if (!signVerified){ throw new WoniuException(500,"支付宝验签不通过");}
        String orderId = params.get("out_trade_no");
        String tradeStatus = params.get("trade_status");
        String payTime = params.get("gmt_payment");
        //更新
        if ("TRADE_SUCCESS".equals(tradeStatus)) {
            GoodOrderInfo goodOrderInfo = goodOrderInfoMapper.selectById(orderId);
            //修改订单状态
            if (goodOrderInfo.getOrderState().equals(StateUtil.GOODS_ORDER_STATE_CANCELLED)) {
                goodOrderInfo.setOrderState(StateUtil.GOODS_ORDER_STATE_NOT_RECEIVED);
            }
            //修改库存
            Set<GoodsDto> goodsDtos = BeanUtil.copyToList(goodOrderInfo.getOrderDetail(), GoodsDto.class).stream().collect(Collectors.toSet());
            Result result = carShoppingClient.reduceFreezeStock(goodsDtos);
            if (result.getCode() != 200) {
                throw new WoniuException(result.getCode(), result.getMsg());
            }
            //支付时间
            LocalDateTime localDateTime = LocalDateTime.parse(payTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            goodOrderInfo.setOrderPayTime(localDateTime.toString());
            goodOrderInfoMapper.updateById(goodOrderInfo);
        }
    }

    @Override
    public GoodOrderInfoDto changeState(GoodOrderInfoChangeStateForm form) {
        GoodOrderInfo goodOrderInfo = goodOrderInfoMapper.selectById(form.getOrderId());
        if (ObjectUtil.isEmpty(goodOrderInfo)) {
            throw new GoodsOrderInfoException(GoodsOrderInfoExceptionCode.GOODS_ORDER_INFO_NOT_EXIST);
        }
        //生成订单日志
        GoodOrderLog goodOrderLog = new GoodOrderLog();
        goodOrderLog.setGoodOrderId(form.getOrderId());
        //时间格式处理器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        goodOrderLog.setLogTime(LocalDateTime.now().format(formatter));
        //如果要取消订单
        if (form.getState().equals(StateUtil.GOODS_ORDER_STATE_CANCELLED)) {
            if (!goodOrderInfo.getOrderState().equals(StateUtil.GOODS_ORDER_STATE_UNPAID)) {
                throw new GoodsOrderInfoException(GoodsOrderInfoExceptionCode.GOODS_ORDER_INFO_STATE_ERROR);
            }
            goodOrderInfo.setOrderState(form.getState());
            int i = goodOrderInfoMapper.updateById(goodOrderInfo);
            if (i != 1) {
                throw new GoodsOrderInfoException(500, "修改商品订单失败");
            }
            //修改库存量
            Set<GoodsDto> goodsDtos = BeanUtil.copyToList(goodOrderInfo.getOrderDetail(), GoodsDto.class).stream().collect(Collectors.toSet());
            Result result = carShoppingClient.addStockAndReduceFreezeStock(goodsDtos);
            if (result.getCode() != 200) {
                throw new WoniuException(result.getCode(), result.getMsg());
            }
            goodOrderLog.setLogDesc(GoodsOrderDescConstants.USER_CANCEL);
        }
        //如果要收货,即将状态改为待评价
        if (form.getState().equals(StateUtil.GOODS_ORDER_STATE_NOT_EVALUATED)) {
            if (!goodOrderInfo.getOrderState().equals(StateUtil.GOODS_ORDER_STATE_NOT_RECEIVED)) {
                throw new GoodsOrderInfoException(GoodsOrderInfoExceptionCode.GOODS_ORDER_INFO_STATE_ERROR);
            }
            goodOrderInfo.setOrderState(form.getState());
            int i = goodOrderInfoMapper.updateById(goodOrderInfo);
            if (i != 1) {
                throw new GoodsOrderInfoException(500, "修改商品订单状态失败");
            }
            goodOrderLog.setLogDesc(GoodsOrderDescConstants.USER_RECEIVED);
        }
        //新增订单日志
        goodOrderLogMapper.insert(goodOrderLog);
        return BeanUtil.toBean(goodOrderInfo, GoodOrderInfoDto.class);
    }
}